package actor

import (
	"errors"
	"google.golang.org/protobuf/encoding/protojson"
	"google.golang.org/protobuf/proto"
	"net"
	"simple_game/app/consts"
	"simple_game/app/libs/logger"
	"simple_game/app/libs/packet_msg"
	"simple_game/app/routes"
	"strconv"
	"time"
)

type IActor interface {
	Loader()
	Start()
	Stop()
}

// https://github.com/devsiscters/ine.git

type Actor struct {
	pid     int64
	name    string
	alive   bool
	mailBox *MessageQueue
	conn    net.Conn
}

func (a *Actor) Pid() int64 {
	return a.pid
}

func (a *Actor) Name() string {
	return a.name
}

func (a *Actor) Loader() {
}

func (a *Actor) Start() {
	// 监听
	go a.loop()
}

func (a *Actor) Stop() {
}

func NewActor(uuid int64, conn net.Conn) *Actor {
	a := new(Actor)
	a.pid = NewPid()
	a.name = strconv.Itoa(int(uuid))
	a.alive = true
	a.mailBox = &MessageQueue{
		limit:   10000,
		request: make(chan interface{}, consts.MsgChannelLen),
		reply:   make(chan bool),
	}
	a.conn = conn
	return a
}

func (a *Actor) loop() {
	for {
		select {
		case req, ok := <-a.mailBox.request:
			if ok {
				//user.DoMsg(msg)
				load, ok := Directors.ActorMap.Load(a.pid)
				if !ok {
					break
				}
				actor := load.(IActor)
				bytes := req.([]byte)

				codePack := packet_msg.DeCodePack(bytes)

				if codePack == nil {
					logger.ERROR("deCodePack error")
					break
				}
				handel, res, err := routes.Route(actor, codePack.Name, codePack.Data)
				if err != nil {
					logger.ERROR("handel is nil! ,handel:", handel)
				} else {
					logger.DEBUG("req:	", codePack.Name)
					marshal, _ := protojson.Marshal(res)
					logger.DEBUG("res:	", proto.MessageName(res).Name(), string(marshal))
					_, _ = a.conn.Write(marshal)
				}
				a.mailBox.reply <- true
			}
		}
	}
}

func (a *Actor) SendMail(msg any) error {
	a.mailBox.request <- msg
	select {
	case <-a.mailBox.reply:
		return nil
	case <-time.After(time.Second * 5):
		return errors.New("time out")
	}
}
